home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / ck5a189s / ckuusx.c < prev    next >
C/C++ Source or Header  |  1993-06-07  |  64KB  |  2,309 lines

  1. /*  C K U U S X --  "User Interface" common functions. */
  2.  
  3. /*
  4.   Author: Frank da Cruz (fdc@columbia.edu, FDCCU@CUVMA.BITNET),
  5.   Columbia University Academic Information Systems, New York City.
  6.  
  7.   Copyright (C) 1985, 1993, Trustees of Columbia University in the City of New
  8.   York.  The C-Kermit software may not be, in whole or in part, licensed or
  9.   sold for profit as a software product itself, nor may it be included in or
  10.   distributed with commercial products or otherwise distributed by commercial
  11.   concerns to their clients or customers without written permission of the
  12.   Office of Kermit Development and Distribution, Columbia University.  This
  13.   copyright notice must not be removed, altered, or obscured.
  14. */
  15.  
  16. /*
  17.   This module contains user interface functions needed by both the interactive
  18.   user interface and the command-line-only user interface.
  19. */
  20.  
  21. /* Includes */
  22.  
  23. #include "ckcdeb.h"
  24. #include "ckcasc.h"
  25. #include "ckcker.h"
  26. #include "ckuusr.h"
  27. #ifndef WINTCP
  28. #include <signal.h>
  29. #endif /* WINTCP */
  30.  
  31. #ifdef VMS
  32. #ifdef WINTCP
  33. #include <descrip.h>
  34. #include <ssdef.h>
  35. #include <stsdef.h>
  36. #include <signal.h>
  37. #else
  38. #include <descrip.h>
  39. #include <ssdef.h>
  40. #include <stsdef.h>
  41. #endif /* WINTCP */
  42. #endif /* VMS */
  43.  
  44. /* Used internally */
  45. _PROTOTYP( VOID screenc, (int, char, long, char *) );
  46. static int ft_win = 0;  /* Fullscreen file transfer display window is active */
  47.  
  48. /* Variables declared here */
  49.  
  50. int fdispla = XYFD_R;            /* File transfer display type */
  51. int tt_crd = 0;                /* Carriage return display */
  52.  
  53. #ifdef DEBUG
  54. char debfil[50];            /* Debugging log file name */
  55. #endif /* DEBUG */
  56.  
  57. #ifdef TLOG
  58. char trafil[50];            /* Transaction log file name */
  59. #endif /* TLOG */
  60.  
  61. char pktfil[50];            /* Packet log file name */
  62. char sesfil[50];            /* Session log file name */
  63.  
  64. #ifndef NOFRILLS
  65. char optbuf[100];            /* Options for MAIL or REMOTE PRINT */
  66. #endif /* NOFRILLS */
  67. char cmdstr[256];            /* Place to build generic command */
  68.  
  69. char fspec[FSPECL];            /* Filename string for \v(filespec) */
  70.  
  71. /*  C C N T A B  --  Names of ASCII control characters 0-31 */
  72.  
  73. char *ccntab[] = { "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
  74.  "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
  75.  "DLE", "DC1/XON", "DC2", "DC3/XOFF", "DC4", "NAK", "SYN", "ETB", "CAN",
  76.  "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
  77. };
  78.  
  79. int success = 1,            /* Command success/failure flag */
  80.  
  81. #ifndef NOSPL
  82.     cmdlvl = 0,                /* Command level */
  83. #endif /* NOSPL */
  84.     action,                /* Action selected on command line*/
  85.     sessft = 0,                /* Session log file type, 0 = text */
  86.     pflag = 1,                /* Print prompt */
  87.     msgflg = 1;                /* Print informational messages */
  88.  
  89. #ifndef NOMSEND                /* Multiple SEND */
  90. char *msfiles[MSENDMAX];
  91. #endif /* NOMSEND */
  92.  
  93. /* External variables */
  94.  
  95. #ifndef NODIAL
  96. extern FILE * dialfd;            /* Dialing directory */
  97. #endif /* NODIAL */
  98.  
  99. extern int local, quiet, binary, bctu, rptflg, ebqflg, network, server,
  100.   what, spsiz, urpsiz, wmax, czseen, cxseen, winlo, displa, timint, parity,
  101.   npad, ebq, ebqflg, bctr, rptq, atcapu, lpcapu, swcapu, wslotn, wslotr, rtimo,
  102.   mypadn, sq, capas, rpsiz, tsecs, dfloc, tralog, pktlog, seslog, lscapu,
  103.   xitsta, escape, tlevel, bgset, backgrd, wslots, suspend, srvdis,
  104.   spackets, spktl, rpktl, retrans, wcur, numerrs, fsecs;
  105.  
  106. #ifdef datageneral            /* 2/12/92 ENH */
  107. #include <sysid.h>
  108. extern int con_reads_mt, conint_ch, conint_avl;
  109. #endif /* datageneral */
  110.  
  111. extern long speed, filcnt, ffc, tfc, rptn, fsize;
  112.  
  113. extern CHAR *rdatap, padch, seol, ctlq, mypadc, eol;
  114.  
  115. extern char ttname[], *dftty, *cmarg, **cmlist, *versio, myhost[];
  116. #ifndef NOICP
  117. #ifdef DCMDBUF
  118. extern char *cmdbuf;            /* Command buffer */
  119. #else
  120. extern char cmdbuf[];            /* Command buffer */
  121. #endif /* DCMDBUF */
  122. #endif /* NOICP */
  123.  
  124. #ifndef NOCCTRAP
  125. #include <setjmp.h>            /* Control-C trap */
  126. jmp_buf cmjbuf;
  127. #endif /* NOCCTRAP */
  128.  
  129. #ifndef NOCSETS
  130. #include "ckcxla.h"
  131. extern int fcharset, tcharset;
  132. extern struct csinfo fcsinfo[], tcsinfo[];
  133. #endif /* NOCSETS */
  134.  
  135. /*  P A R N A M  --  Return parity name */
  136.  
  137. char *
  138. #ifdef CK_ANSIC
  139. parnam(char c)
  140. #else
  141. parnam(c) char c;
  142. #endif /* CK_ANSIC */
  143. /* parnam */ {
  144.     switch (c) {
  145.     case 'e': return("even");
  146.     case 'o': return("odd");
  147.     case 'm': return("mark");
  148.     case 's': return("space");
  149.     case 0:   return("none");
  150.     default:  return("invalid");
  151.     }
  152. }
  153.  
  154. /*  S H O M D M  --  Show modem signals  */
  155.  
  156. VOID
  157. shomdm() {
  158. /*
  159.   Note use of "\r\n" to make sure this report prints right, even when
  160.   called during CONNECT mode.
  161. */
  162.     int y;
  163.     y = ttgmdm();
  164.     switch (y) {
  165.       case -3: printf(
  166.              "Modem signals unavailable in this version of Kermit\r\n");
  167.            break;
  168.       case -2: printf("No modem control for this device\r\n"); break;
  169.       case -1: printf("Modem signals unavailable\r\n"); break;
  170.       default:
  171. #ifndef MAC
  172.         printf(
  173.       " Carrier Detect      (CD):  %s\r\n",(y & BM_DCD) ? "On": "Off");
  174.     printf(
  175.           " Dataset Ready       (DSR): %s\r\n",(y & BM_DSR) ? "On": "Off");
  176. #endif /* MAC */
  177.     printf(
  178.           " Clear To Send       (CTS): %s\r\n",(y & BM_CTS) ? "On": "Off");
  179. #ifndef MAC
  180.         printf(
  181.           " Ring Indicator      (RI):  %s\r\n",(y & BM_RNG) ? "On": "Off");
  182. #endif /* MAC */
  183.         printf(
  184.           " Data Terminal Ready (DTR): %s\r\n",(y & BM_DTR) ? "On": "Off");
  185. #ifndef MAC
  186.         printf(
  187.           " Request to Send     (RTS): %s\r\n",(y & BM_RTS) ? "On": "Off");
  188. #endif /* MAC */
  189.     }
  190. }
  191.  
  192. /*  S D E B U  -- Record spar results in debugging log  */
  193.  
  194. VOID
  195. sdebu(len) int len; {
  196.     debug(F111,"spar: data",(char *) rdatap,len);
  197.     debug(F101," spsiz ","", spsiz);
  198.     debug(F101," timint","",timint);
  199.     debug(F101," npad  ","",  npad);
  200.     debug(F101," padch ","", padch);
  201.     debug(F101," seol  ","",  seol);
  202.     debug(F101," ctlq  ","",  ctlq);
  203.     debug(F101," ebq   ","",   ebq);
  204.     debug(F101," ebqflg","",ebqflg);
  205.     debug(F101," bctr  ","",  bctr);
  206.     debug(F101," rptq  ","",  rptq);
  207.     debug(F101," rptflg","",rptflg);
  208.     debug(F101," lscapu","",lscapu);
  209.     debug(F101," atcapu","",atcapu);
  210.     debug(F101," lpcapu","",lpcapu);
  211.     debug(F101," swcapu","",swcapu);
  212.     debug(F101," wslotn","", wslotn);
  213. }
  214. /*  R D E B U -- Debugging display of rpar() values  */
  215.  
  216. VOID
  217. rdebu(d,len) CHAR *d; int len; {
  218.     debug(F111,"rpar: data",d,len);
  219.     debug(F101," rpsiz ","", xunchar(d[0]));
  220.     debug(F101," rtimo ","", rtimo);
  221.     debug(F101," mypadn","",mypadn);
  222.     debug(F101," mypadc","",mypadc);
  223.     debug(F101," eol   ","",   eol);
  224.     debug(F101," ctlq  ","",  ctlq);
  225.     debug(F101," sq    ","",    sq);
  226.     debug(F101," ebq   ","",   ebq);
  227.     debug(F101," ebqflg","",ebqflg);
  228.     debug(F101," bctr  ","",  bctr);
  229.     debug(F101," rptq  ","",  d[8]);
  230.     debug(F101," rptflg","",rptflg);
  231.     debug(F101," capas ","", capas);
  232.     debug(F101," bits  ","",d[capas]);
  233.     debug(F101," lscapu","",lscapu);
  234.     debug(F101," atcapu","",atcapu);
  235.     debug(F101," lpcapu","",lpcapu);
  236.     debug(F101," swcapu","",swcapu);
  237.     debug(F101," wslotr","", wslotr);
  238.     debug(F101," rpsiz(extended)","",rpsiz);
  239. }
  240.  
  241. #ifdef COMMENT
  242. /*  C H K E R R  --  Decide whether to exit upon a protocol error  */
  243.  
  244. VOID
  245. chkerr() {
  246.     if (backgrd && !server) fatal("Protocol error");
  247. }
  248. #endif /* COMMENT */
  249.  
  250. /*  F A T A L  --  Fatal error message */
  251.  
  252. VOID
  253. fatal(msg) char *msg; {
  254.     if (!msg) msg = "";
  255. #ifdef VMS
  256.     if (strncmp(msg,"%CKERMIT",8))
  257.       conol("%CKERMIT-E-FATAL, ");
  258.     conoll(msg);
  259. #else /* !VMS */
  260.     screen(SCR_EM,0,0L,msg);
  261. #endif /* VMS */
  262.     debug(F110,"fatal",msg,0);
  263.     tlog(F110,"Fatal:",msg,0L);
  264.     doexit(BAD_EXIT,xitsta | 1);    /* Exit indicating failure */
  265. }
  266.  
  267. /*  B L D L E N  --  Make length-encoded copy of string  */
  268.  
  269. char *
  270. bldlen(str,dest) char *str, *dest; {
  271.     int len;
  272.     len = (int)strlen(str);
  273.     *dest = tochar(len);
  274.     strcpy(dest+1,str);
  275.     return(dest+len+1);
  276. }
  277.  
  278.  
  279. /*  S E T G E N  --  Construct a generic command  */
  280.  
  281. CHAR
  282. #ifdef CK_ANSIC
  283. setgen(char type,char * arg1, char * arg2, char * arg3)
  284. #else
  285. setgen(type,arg1,arg2,arg3) char type, *arg1, *arg2, *arg3;
  286. #endif /* CK_ANSIC */
  287. /* setgen */ {
  288.     char *upstr, *cp;
  289.  
  290.     cp = cmdstr;
  291.     *cp++ = type;
  292.     *cp = NUL;
  293.     if (*arg1 != NUL) {
  294.     upstr = bldlen(arg1,cp);
  295.     if (*arg2 != NUL) {
  296.         upstr = bldlen(arg2,upstr);
  297.         if (*arg3 != NUL) bldlen(arg3,upstr);
  298.     }
  299.     }
  300.     cmarg = cmdstr;
  301.     debug(F110,"setgen",cmarg,0);
  302.  
  303.     return('g');
  304. }
  305.  
  306. #ifndef NOMSEND
  307. static char *mgbufp = NULL;
  308.  
  309. /*  F N P A R S E  --  */
  310.  
  311. /*
  312.   Argument is a character string containing one or more filespecs.
  313.   This function breaks the string apart into an array of pointers, one
  314.   to each filespec, and returns the number of filespecs.  Used by server
  315.   when it receives a GET command to allow it to process multiple file
  316.   specifications in one transaction.  Sets cmlist to point to a list of
  317.   file pointers, exactly as if they were command line arguments.
  318.  
  319.   This version of fnparse treats spaces as filename separators.  If your
  320.   operating system allows spaces in filenames, you'll need a different
  321.   separator.
  322.  
  323.   This version of fnparse mallocs a string buffer to contain the names.  It
  324.   cannot assume that the string that is pointed to by the argument is safe.
  325. */
  326. int
  327. fnparse(string) char *string; {
  328.     char *p, *s, *q;
  329.     int r = 0, x;            /* Return code */
  330.  
  331.     if (mgbufp) free(mgbufp);        /* Free this from last time. */
  332.     mgbufp = malloc((int)strlen(string)+2);
  333.     if (!mgbufp) {
  334.     debug(F100,"fnparse malloc error","",0);
  335.     return(0);
  336.     }    
  337. #ifndef NOICP
  338. #ifndef NOSPL
  339.     strncpy(fspec,string,FSPECL);    /* Make copy for \v(filespec) */
  340. #endif /* NOSPL */
  341. #endif /* NOICP */
  342.     s = string;                /* Input string */
  343.     p = q = mgbufp;            /* Point to the copy */
  344.     r = 0;                /* Initialize our return code */
  345.     while (*s == SP || *s == HT)    /* Skip leading spaces and tabs */
  346.       s++;
  347.     for (x = strlen(s);            /* Strip trailing spaces */
  348.      (x > 1) && (s[x-1] == SP || s[x-1] == HT);
  349.      x--)
  350.       s[x-1] = NUL;
  351.     while (1) {                /* Loop through rest of string */
  352.     if (*s == CMDQ) {        /* Backslash (quote character)? */
  353.         if ((x = xxesc(&s)) > -1) {    /* Go interpret it. */
  354.         *q++ = (char) x;    /* Numeric backslash code, ok */
  355.         } else {            /* Just let it quote next char */
  356.         s++;            /* get past the backslash */
  357.         *q++ = *s++;        /* deposit next char */
  358.         }
  359.         continue;
  360.     } else if (*s == SP || *s == NUL) { /* Unquoted space or NUL? */
  361.         *q++ = NUL;            /* End of output filename. */
  362.         msfiles[r] = p;        /* Add this filename to the list */
  363.         debug(F111,"fnparse",msfiles[r],r);
  364.         r++;            /* Count it */
  365.         if (*s == NUL) break;    /* End of string? */
  366.         while (*s == SP) s++;    /* Skip repeated spaces */
  367.         p = q;            /* Start of next name */
  368.         continue;
  369.     } else *q++ = *s;        /* Otherwise copy the character */
  370.     s++;                /* Next input character */
  371.     }
  372.     debug(F101,"fnparse r","",r);
  373.     msfiles[r] = "";            /* Put empty string at end of list */
  374.     cmlist = msfiles;
  375.     return(r);
  376. }
  377. #endif /* NOMSEND */
  378.  
  379. char *                    /* dbchr() for DEBUG SESSION */
  380. dbchr(c) int c; {
  381.     static char s[8];
  382.     char *cp = s;
  383.  
  384.     c &= 0xff;
  385.     if (c & 0x80) {            /* 8th bit on */
  386.     *cp++ = '~';
  387.     c &= 0x7f;
  388.     }
  389.     if (c < SP) {            /* Control character */
  390.     *cp++ = '^';
  391.     *cp++ = ctl(c);
  392.     } else if (c == DEL) {
  393.     *cp++ = '^';
  394.     *cp++ = '?';
  395.     } else {                /* Printing character */
  396.     *cp++ = c;
  397.     }
  398.     *cp = '\0';                /* Terminate string */
  399.     cp = s;                /* Return pointer to it */
  400.     return(cp);
  401. }
  402.  
  403. /*  C K H O S T  --  Get name of local host (where C-Kermit is running)  */
  404.  
  405. /*
  406.   Call with pointer to buffer to put hostname in, and length of buffer.
  407.   Copies hostname into buffer on success, puts null string in buffer on
  408.   failure.
  409. */
  410. #ifdef BSD44
  411. #define BSD4
  412. #undef ATTSV
  413. #endif /* BSD44 */
  414.  
  415. #ifdef SVORPOSIX
  416. #ifndef BSD44
  417. #include <sys/utsname.h>
  418. #endif /* BSD44 */
  419. #endif /* SVORPOSIX*/
  420.  
  421. VOID
  422. ckhost(vvbuf,vvlen) char * vvbuf; int vvlen; {
  423.     char *g;
  424. #ifdef VMS
  425.     int x;
  426. #endif /* VMS */
  427. #ifdef SVORPOSIX
  428. #ifndef BSD44
  429.     struct utsname hname;
  430. #endif /* BSD44 */
  431. #endif /* SVORPOSIX */
  432. #ifdef datageneral
  433.     int ac0 = (char *) vvbuf, ac1 = -1, ac2 = 0;
  434. #endif /* datageneral */
  435.  
  436.     *vvbuf = NUL;
  437. #ifndef OXOS
  438. #ifdef SVORPOSIX
  439. #ifdef BSD44
  440.     if (gethostname(vvbuf,vvlen) < 0) *vvbuf = NUL;
  441. #else
  442.     if (uname(&hname) > -1) strncpy(vvbuf,hname.nodename,vvlen);
  443. #endif /* BSD44 */
  444. #else
  445. #ifdef BSD4
  446.     if (gethostname(vvbuf,vvlen) < 0) *vvbuf = NUL;
  447. #else
  448. #ifdef VMS
  449.     g = getenv("SYS$NODE");
  450.     if (g) strncpy(vvbuf,g,vvlen);
  451.     x = (int)strlen(vvbuf);
  452.     if (x > 1 && vvbuf[x-1] == ':' && vvbuf[x-2] == ':') vvbuf[x-2] = NUL;
  453. #else
  454. #ifdef datageneral
  455.     if (sys($HNAME,&ac0,&ac1,&ac2) == 0) /* successful */
  456.         vvlen = ac2 + 1;        /* enh - have to add one */
  457. #else
  458. #ifdef OS2                /* OS/2 */
  459.     g = getenv("SYSTEMNAME");
  460.     if (!g) g = getenv("HOSTNAME");
  461.     if (g) strncpy(vvbuf,g,vvlen);
  462. #endif /* OS2 */
  463. #endif /* datageneral */
  464. #endif /* VMS */
  465. #endif /* BSD4 */
  466. #endif /* SVORPOSIX */
  467. #else /* OXOS */
  468.     /* If TCP/IP is not installed, gethostname() fails, use uname() */
  469.     if (gethostname(vvbuf,vvlen) < 0) {
  470.     if (uname(&hname) > -1)
  471.         strncpy(vvbuf,hname.nodename,vvlen);
  472.     else
  473.         *vvbuf = NUL;
  474.     }
  475. #endif /* OXOS */
  476.     if (*vvbuf == NUL) {        /* If it's still empty */
  477.         g = getenv("HOST");        /* try this */
  478.         if (g) strncpy(vvbuf,g,vvlen);
  479.     }
  480.     vvbuf[vvlen-1] = NUL;        /* Make sure result is terminated. */
  481. }
  482. #ifdef BSD44
  483. #undef BSD4
  484. #define ATTSV
  485. #endif /* BSD44 */
  486.  
  487.  
  488. #ifndef NOSPL
  489. #define ASKMORE
  490. #endif /* NOSPL */
  491. #ifndef NOHELP
  492. #ifndef ASKMORE
  493. #define ASKMORE
  494. #endif /* ASKMORE */
  495. #endif /* NOHELP */
  496.  
  497. #ifdef ASKMORE
  498. /*
  499.   A S K M O R E  --  Poor person's "more".
  500.   Returns 0 if no more, 1 if more wanted.
  501.   Presently used by SHO MAC, SHO GLOB, SHO VAR, and HELP, so compiled out if
  502.   those options are also compiled out.
  503. */
  504. int
  505. askmore() {
  506.     char c; int rv;
  507.  
  508.     rv = -1;
  509.     while (rv < 0) {
  510. #ifndef OS2
  511.     printf("more? ");
  512. #ifdef UNIX
  513. #ifdef NOSETBUF
  514.     fflush(stdout);
  515. #endif /* NOSETBUF */
  516. #endif /* UNIX */
  517. #else
  518.     printf("more? (Y or space-bar for yes, N for no) ");
  519.     fflush(stdout);
  520. #endif /* OS2 */
  521.     c = coninc(0);
  522.     switch (c) {
  523.       /* Yes */
  524.       case SP: case 'y': case 'Y': case 012:  case 015:
  525.         printf("\015      \015");
  526.         rv = 1;
  527.         break;
  528.           /* No */
  529.       case 'n': case 'N': case 'q': case 'Q':
  530.         printf("\015\012");
  531.         rv = 0;
  532.         break;
  533.       /* Invalid answer */
  534.       default:
  535.         printf("Y or space-bar for yes, N for no\n");
  536.         continue;
  537.     }
  538. #ifdef OS2
  539.     printf("\r                                         \r");
  540.     fflush(stdout);
  541. #endif /* OS2 */
  542.     }
  543.     return(rv);
  544. }
  545. #endif /* ASKMORE */
  546.  
  547. /*  T R A P  --  Terminal interrupt handler */
  548.  
  549. SIGTYP
  550. trap(sig) int sig; {
  551. #ifdef VMS
  552.     int i; FILE *f;
  553. #endif /* VMS */
  554. #ifdef __EMX__
  555.   signal(SIGINT, SIG_ACK);
  556. #endif
  557. #ifdef GEMDOS
  558. /* GEM is not reentrant, no i/o from interrupt level */
  559.     longjmp(cmjbuf,1);            /* Jump back to parser now! */
  560. #endif /* GEMDOS */
  561.     debug(F101,"^C trap() caught signal","",sig);
  562.     zclose(ZIFILE);            /* If we were transferring a file, */
  563.     zclose(ZOFILE);            /* close it. */
  564. #ifdef VMS
  565. /*
  566.   Fix terminal.
  567. */
  568.     if (ft_win) {            /* If curses window open */
  569.     screen(SCR_CW,0,0L,"");        /* Close it */
  570.     conres();            /* Restore terminal */
  571.     i = printf("^C...");        /* Echo ^C to standard output */
  572.     } else {
  573.     conres();
  574.     i = printf("^C...\n");        /* Echo ^C to standard output */
  575.     }
  576.     if (i < 1 && ferror(stdout)) {    /* If there was an error */
  577.     fclose(stdout);            /* close standard output */
  578.     f = fopen(dftty, "w");        /* open the controlling terminal */
  579.     if (f) stdout = f;        /* and make it standard output */
  580.     printf("^C...\n");        /* and echo the ^C again. */
  581.     }
  582. #else                    /* Not VMS */
  583.     if (ft_win) {            /* If curses window open, */
  584.     screen(SCR_CW,0,0L,"");        /* close it. */
  585.     printf("^C...");        /* Echo ^C to standard output */
  586.     } else {
  587.     printf("^C...\n");
  588.     }
  589. #endif /* VMS */
  590. #ifdef datageneral
  591.     connoi_mt();             /* Kill asynch task that listens to */
  592.     ttimoff();                /* the keyboard */
  593.     conres();
  594. #endif /* datageneral */
  595.  
  596. #ifndef NOCCTRAP
  597. #ifdef UNIX
  598.     ttimoff();                /* Turn off any timer interrupts */
  599. #endif /* UNIX */
  600. #ifdef OSK
  601.     ttimoff();                /* Turn off any timer interrupts */
  602.     sigmask(-1);
  603. /*
  604.   We are in an intercept routine but do not perform a F$RTE (done implicitly
  605.   but rts).  We have to decrement the sigmask as F$RTE does.  Warning:
  606.   longjump only restores the cpu registers, NOT the fpu registers.  So don't
  607.   use fpu at all or at least don't use common fpu (double or float) register
  608.   variables.
  609. */
  610. #endif /* OSK */
  611.     longjmp(cmjbuf,1);            /* Jump back to parser */
  612. #else
  613. /* No Ctrl-C trap, just exit. */
  614. #ifdef CK_CURSES            /* Curses support? */
  615.     screen(SCR_CW,0,0L,"");        /* Close curses window */
  616. #endif /* CK_CURSES */
  617.     doexit(BAD_EXIT,what);        /* Exit poorly */
  618. #endif /* NOCCTRAP */
  619.     SIGRETURN;
  620. }
  621.  
  622. /*  C C _ C L E A N  --  Cleanup after terminal interrupt handler */
  623.  
  624. #ifdef GEMDOS
  625. int
  626. cc_clean() {
  627.     zclose(ZIFILE);            /* If we were transferring a file, */
  628.     zclose(ZOFILE);            /* close it. */
  629.     printf("^C...\n");            /* Not VMS, no problem... */
  630. }
  631. #endif /* GEMDOS */
  632.  
  633.  
  634. /*  S T P T R A P -- Handle SIGTSTP (suspend) signals */
  635.  
  636. SIGTYP
  637. stptrap(sig) int sig; {
  638. #ifndef NOJC
  639.     int x; extern int cmflgs;
  640.     debug(F101,"stptrap() caught signal","",sig);
  641.     if (!suspend) {
  642.     printf("\r\nsuspend disabled\r\n");
  643. #ifndef NOICP
  644.     if (what == W_COMMAND) {    /* If we were parsing commands */
  645.         prompt(xxstring);        /* reissue the prompt and partial */
  646.         if (!cmflgs)        /* command (if any) */
  647.           printf("%s",cmdbuf);
  648.     }
  649. #endif /* NOICP */
  650.     } else {
  651.     conres();            /* Reset the console */
  652. #ifndef OS2
  653.     /* Flush pending output first, in case we are continued */
  654.     /* in the background, which could make us block */
  655.     fflush(stdout);
  656.  
  657.     x = psuspend(suspend);        /* Try to suspend. */
  658.     if (x < 0)
  659. #endif /* OS2 */
  660.       printf("Job control not supported\r\n");
  661.     conint(trap,stptrap);        /* Rearm the trap. */
  662.     debug(F100,"stptrap back from suspend","",0);
  663.     switch (what) {
  664.       case W_CONNECT:        /* If suspended during CONNECT? */
  665.         conbin((char)escape);    /* put console back in binary mode */
  666.         debug(F100,"stptrap W_CONNECT","",0);
  667.         break;
  668. #ifndef NOICP
  669.       case W_COMMAND:        /* Suspended in command mode */
  670.         debug(F101,"stptrap W_COMMAND pflag","",pflag);
  671.         concb((char)escape);    /* Put back CBREAK tty mode */
  672.         if (pflag) {        /* If command parsing was */
  673.         prompt(xxstring);    /* reissue the prompt and partial */
  674.         if (!cmflgs)        /* command (if any) */
  675.           printf("%s",cmdbuf);
  676.         }
  677.         break;
  678. #endif /* NOICP */
  679.       default:            /* All other cases... */
  680.         debug(F100,"stptrap default","",0);
  681.         concb((char)escape);    /* Put it back in CBREAK mode */
  682.         break;
  683.     }
  684.     }
  685. #endif /* NOJC */
  686.     SIGRETURN;
  687. }
  688.  
  689. #ifndef MAC
  690. /*
  691.   The rest of this file is for all implementations but the Macintosh.
  692. */
  693.  
  694. /*  C H K I N T  --  Check for console interrupts  */
  695.  
  696. int
  697. chkint() {
  698.     int ch, cn; long zz;
  699.  
  700.     if ((!local) || (quiet)) return(0);    /* Only do this if local & not quiet */
  701. #ifdef datageneral
  702.     if (con_reads_mt)                   /* if conint_mt task is active */
  703.         if (conint_avl) {               /* and there's an interrupt pending */
  704.             cn = 1;                     /* process it */
  705.             ch = conint_ch;
  706.             conint_avl = 0;             /* turn off flag so conint_mt can */
  707.         } else                          /* proceed */
  708.             return(0);
  709.     else                                /* if conint_mt not active */
  710.         if ((ch = coninc(2)) < 0)       /* try to get char manually */
  711.             return(0);                  /* I/O error, or no data */
  712.         else                            /* if successful, set cn so we */
  713.             cn = 1;                     /* know we got one */
  714.     debug(F101,"chkint got keyboard character",ch,cn);
  715. #else
  716.     cn = conchk();            /* Any input waiting? */
  717.     debug(F101,"conchk","",cn);
  718.     if (cn < 1) return(0);
  719.     if ((ch = coninc(5)) < 0) return(0);
  720. #endif /* datageneral */
  721.  
  722.     switch (ch & 0177) {
  723.       case 'A': case 'a': case 0001:        /* Status report */
  724.     if (fdispla != XYFD_R && fdispla != XYFD_S)
  725.       return(0);                            /* Only for serial or simple */
  726.     screen(SCR_TN,0,0l,"Status report:");
  727.     screen(SCR_TN,0,0l," file type: ");
  728.     if (binary) {
  729. #ifdef VMS
  730.         if (binary == XYFT_I)        /* VMS-only file types */
  731.           screen(SCR_TZ,0,0l,"image");
  732.         else if (binary == XYFT_L)
  733.           screen(SCR_TZ,0,0l,"labeled");
  734.         else screen(SCR_TZ,0,0l,"binary");
  735. #else
  736.         screen(SCR_TZ,0,0l,"binary");
  737. #endif /* VMS */
  738.     } else {
  739. #ifdef NOCSETS
  740.         screen(SCR_TZ,0,0l,"text");
  741. #else
  742.         screen(SCR_TU,0,0l,"text, ");
  743.         if (tcharset == TC_TRANSP) {
  744.         screen(SCR_TZ,0,0l,"transparent");
  745.         } else {
  746.         if (what == W_SEND) {
  747.             screen(SCR_TZ,0,0l,tcsinfo[tcharset].keyword);
  748.             screen(SCR_TU,0,0l," => ");
  749.             screen(SCR_TZ,0,0l,fcsinfo[fcharset].keyword);
  750.         } else {
  751.             screen(SCR_TZ,0,0l,fcsinfo[fcharset].keyword);
  752.             screen(SCR_TU,0,0l," => ");
  753.             screen(SCR_TZ,0,0l,tcsinfo[tcharset].keyword);
  754.         }
  755.         }
  756. #endif /* NOCSETS */
  757.     }
  758.     screen(SCR_QE,0,filcnt," file number");
  759.     if (fsize) screen(SCR_QE,0,fsize," size");
  760.     screen(SCR_QE,0,ffc,   " characters so far");
  761.     if (fsize > 0L) {
  762.         zz = ( ffc * 100L ) / fsize;
  763.         screen(SCR_QE,0,zz,      " percent done");
  764.     }
  765.     if (bctu == 4) {        /* Block check */
  766.         screen(SCR_TU,0,0L," block check: ");
  767.         screen(SCR_TZ,0,0L,"blank-free-2");
  768.     } else screen(SCR_QE,0,(long)bctu,  " block check");
  769.     screen(SCR_QE,0,(long)rptflg," compression");
  770.     screen(SCR_QE,0,(long)ebqflg," 8th-bit prefixing");
  771.     screen(SCR_QE,0,(long)lscapu," locking shifts");
  772.     if (!network)
  773.       screen(SCR_QE,0, speed, " speed");
  774.     if (what == W_SEND)
  775.       screen(SCR_QE,0,(long)spsiz, " packet length");
  776.     else if (what == W_RECV || what == W_REMO)
  777.       screen(SCR_QE,0,(long)urpsiz," packet length");
  778.     screen(SCR_QE,0,(long)wslots,  " window slots");
  779.     return(0);
  780.  
  781.       case 'B': case 'b': case 0002:    /* Cancel batch */
  782.       case 'Z': case 'z': case 0032:
  783.     screen(SCR_TN,0,0l,"Cancelling Batch ");
  784.     czseen = 1;
  785.     return(0);
  786.  
  787.       case 'F': case 'f': case 0006:    /* Cancel file */
  788.       case 'X': case 'x': case 0030:
  789.     screen(SCR_TN,0,0l,"Cancelling File ");
  790.     cxseen = 1;
  791.     return(0);
  792.  
  793.       case 'R': case 'r': case 0022:    /* Resend */
  794.       case 0015: case 0012:
  795.     screen(SCR_TN,0,0l,"Resending packet ");
  796.     numerrs++;
  797.     resend(winlo);
  798.     return(1);
  799.  
  800.       case 'E': case 'e':        /* Send error packet */
  801.       case 0005:
  802.     return(-1);
  803.  
  804. #ifdef datageneral
  805.       case '\03':                       /* We're not trapping ^C's with */
  806.         trap(0);                        /* signals, so we check here    */
  807. #endif /* datageneral */
  808.  
  809.       default:                /* Anything else, print message */
  810.     intmsg(1L);
  811.     return(0);
  812.     }
  813. }
  814.  
  815. /*  I N T M S G  --  Issue message about terminal interrupts  */
  816.  
  817. VOID
  818. #ifdef CK_ANSIC
  819. intmsg(long n)
  820. #else
  821. intmsg(n) long n;
  822. #endif /* CK_ANSIC */
  823. /* intmsg */ {
  824.     char buf[80];
  825.  
  826.     if (!displa || quiet)        /* Not if we're being quiet */
  827.       return;
  828.     if (server && (!srvdis || n > -1L))    /* Special for server */
  829.       return;
  830.     buf[0] = NUL;            /* Keep compilers happy */
  831. #ifndef OXOS
  832. #ifdef SVORPOSIX
  833.     conchk();                /* Clear out pending escape-signals */
  834. #endif /* SVORPOSIX */
  835. #endif /* ! OXOS */
  836. #ifdef VMS
  837.     conres();                /* So Ctrl-C will work */
  838. #endif /* VMS */
  839.     if ((!server && n == 1L) || (server && n < 0L)) {
  840.  
  841. #ifdef SVORPOSIX            /* We need to signal before kb input */
  842. #ifndef aegis
  843. #ifndef datageneral
  844. #ifndef OXOS
  845. #ifndef CK_POLL
  846.     sprintf(buf,"Type escape character (%s) followed by:",dbchr(escape));
  847.     screen(SCR_TN,0,0l,buf);
  848. #endif /* CK_POLL */
  849. #endif /* ! OXOS */
  850. #endif /* datageneral */
  851. #endif /* aegis */
  852. #endif /* SVORPOSIX */
  853.  
  854.  screen(SCR_TN,0,0l,"X to cancel file,  CR to resend current packet");
  855.  screen(SCR_TN,0,0l,"Z to cancel group, A for status report");
  856.  screen(SCR_TN,0,0l,"E to send Error packet, Ctrl-C to quit immediately: ");
  857. /* if (server) */ screen(SCR_TN,0,0l,"");
  858.     }
  859.     else screen(SCR_TU,0,0l," ");
  860. }
  861.  
  862. static int newdpy = 0;            /* New display flag */
  863. static char fbuf[80];            /* Filename buffer */
  864. static char abuf[80];            /* As-name buffer */
  865. static long oldffc = 0L;
  866. static long dots = 0L;
  867. static int hpos = 0;
  868.  
  869. static VOID                /* Initialize Serial or CTR display */
  870. dpyinit() {
  871.     newdpy = 0;                /*  Don't do this again */
  872.     oldffc = 0L;            /*  Reset this */
  873.     dots = 0L;                /*  and this.. */
  874.     conoll("");                        /* New line */
  875.     if (what == W_SEND) conol("Sending: ");         /* Action */
  876.     else if (what == W_RECV) conol("Receiving: ");
  877.     conol(fbuf);
  878.     if (*abuf) conol(" => "); conoll(abuf);         /* Names */
  879.     *fbuf = NUL; *abuf = NUL;
  880.     if (fsize > -1L) {                    /* Size */
  881.     sprintf(fbuf,"Size: %ld, Type: ",fsize);
  882.     conol(fbuf); *fbuf = NUL;
  883.     } else conol("Size: unknown, Type: ");
  884.     if (binary) {                    /* Type */
  885. #ifdef VMS
  886.     if (binary == XYFT_I)        /* VMS-only file types */
  887.       conoll("image");
  888.     else if (binary == XYFT_L)
  889.       conoll("labeled");
  890.     else
  891. #endif /* VMS */
  892.       conoll("binary");
  893.     } else {
  894. #ifdef NOCSETS
  895.     conoll("text");
  896. #else
  897.     conol("text, ");
  898.     if (tcharset == TC_TRANSP) {
  899.         conoll("transparent");
  900.     } else {
  901.         if (what == W_SEND) {
  902.         conol(fcsinfo[fcharset].keyword);
  903.         conol(" => ");
  904.         conoll(tcsinfo[tcharset].keyword);
  905.         } else {
  906.         conol(tcsinfo[tcharset].keyword);
  907.         conol(" => ");
  908.         conoll(fcsinfo[fcharset].keyword);
  909.         }
  910.     }
  911. #endif /* NOCSETS */
  912.     }
  913.     if (fdispla == XYFD_S) {        /* CRT field headings */
  914. /*
  915.   Define CK_CPS to show current transfer rate.
  916.   Leave it undefined to show estimated time remaining.
  917.   Estimated-time-remaining code from Andy Fyfe, not tested on
  918.   pathological cases.
  919. */
  920. #define CK_CPS
  921.  
  922. #ifdef CK_CPS
  923.     conoll("    File   Percent       Packet");
  924.     conoll("    Bytes  Done     CPS  Length");
  925. #else
  926.     conoll("    File   Percent  Secs Packet");
  927.     conoll("    Bytes  Done     Left Length");
  928. #endif /* CK_CPS */
  929.     newdpy = 0;
  930.     }
  931.     hpos = 0;
  932. }
  933.  
  934. /*
  935.   showpkt(c)
  936.   c = completion code: 0 means transfer in progress, nonzero means it's done.
  937.   show the file transfer progress counter and perhaps verbose packet type.
  938.   Original by: Kai Uwe Rommel.
  939. */
  940. VOID
  941. #ifdef CK_ANSIC
  942. showpkt(char c)
  943. #else
  944. showpkt(c) char c;
  945. #endif /* CK_ANSIC */
  946. /* showpkt */ {
  947.  
  948.     if (newdpy)                /* Put up filenames, etc, */
  949.       dpyinit();            /* if they're not there already. */
  950.  
  951.     if (fdispla == XYFD_S) {        /* CRT display */
  952.     char buffer[40];
  953.     long et;            /* Elapsed time, entire batch  */
  954.     long pd;            /* Percent done, this file     */
  955.     long tp;            /* Transfer rate, entire batch */
  956.     long ps;            /* Packet size, current packet */
  957.     long mytfc;            /* Local copy of byte counter  */
  958.  
  959.     et = gtimer();            /* Elapsed time  */
  960.     ps = (what == W_RECV) ? rpktl+1 : spktl+1; /* Packet length */
  961.     pd = -1;            /* Percent done. */
  962.     if (c == NUL) {            /* Still going, figure % done */
  963.         if (fsize == 0L) return;    /* Empty file, don't bother */
  964.         pd = (fsize > 99L) ? (ffc / (fsize / 100L)) : 0L;
  965.         if (pd > 100) pd = 100;    /* Expansion */
  966.     } else pd = 100;        /* File complete, so 100%. */
  967.  
  968. #ifndef CK_CPS
  969. /*
  970.   fsecs = time (from gtimer) that this file started (set in sfile()).
  971.   Rate so far is ffc / (et - fsecs),  estimated time for remaining bytes
  972.   is (fsize - ffc) / ( ffc / (et - fsecs )).
  973. */
  974.     tp = (ffc > 0L) ? (fsize - ffc) * (et - fsecs) / ffc : 0L;
  975. #endif /* CK_CPS */
  976.  
  977. #ifdef CK_CPS
  978.     mytfc = (pd < 100) ? tfc + ffc : tfc;
  979.     tp = (et > 0) ? mytfc / et : 0; /* Transfer rate */
  980.     if (c && (tp == 0))        /* Watch out for subsecond times */
  981.       tp = ffc;
  982. #endif /* CK_CPS */
  983.     if (pd > -1L)
  984.       sprintf(buffer, "%c%9ld%5ld%%%8ld%8ld ", CR, ffc, pd, tp, ps);
  985.     else
  986.       sprintf(buffer, "%c%9ld      %8ld%8ld ", CR, ffc, tp, ps);
  987.     conol(buffer);
  988.     hpos = 31;
  989.     } else {                /* SERIAL display */
  990.     long i, k;
  991.     if (ffc - oldffc < 1024)    /* Update display every 1K */
  992.       return;
  993.     oldffc = ffc;            /* Time for new display */
  994.     k = (ffc / 1024L) - dots;    /* How many K so far */
  995.     for (i = 0L; i < k; i++) {
  996.         if (hpos++ > 77) {        /* Time to wrap? */
  997.         conoll("");
  998.         hpos = 0;
  999.         }
  1000.         conoc('.');            /* Print a dot for this K */
  1001.         dots++;            /* Count it */
  1002.     }
  1003.     }
  1004. }
  1005.  
  1006. /*  S C R E E N  --  Screen display function  */
  1007.  
  1008. /*
  1009.   screen(f,c,n,s)
  1010.     f - argument descriptor
  1011.     c - a character or small integer
  1012.     n - a long integer
  1013.     s - a string.
  1014.   Fill in this routine with the appropriate display update for the system.
  1015.     FILE DISPLAY SERIAL:     Default, works on any terminal, even hardcopy.
  1016.     FILE DISPLAY CRT:        Works on any CRT, writes over current line.
  1017.     FILE DISPLAY FULLSCREEN: Requires terminal-dependent screen control.
  1018. */
  1019. VOID
  1020. #ifdef CK_ANSIC
  1021. screen(int f, char c,long n,char *s)
  1022. #else
  1023. screen(f,c,n,s) int f; char c; long n; char *s;
  1024. #endif /* CK_ANSIC */
  1025. /* screen */ {
  1026.     char buf[80];
  1027.     int len;                /* Length of string */
  1028. #ifdef UNIX
  1029. #ifndef NOJC
  1030.     int obg;
  1031. _PROTOTYP( VOID conbgt, (int) );
  1032.  
  1033.     if (local) {
  1034.     obg = backgrd;            /* Previous background status */
  1035.     conbgt(1);            /* See if running in background */
  1036.     if (!backgrd && obg) {        /* Just came into foreground? */
  1037.         concb((char)escape);    /* Put console back in CBREAK mode */
  1038.         conint(trap,stptrap);    /* Turn interrupts back on. */
  1039.     }
  1040.     }
  1041. #endif /* NOJC */
  1042. #endif /* UNIX */
  1043.  
  1044.     if ((f != SCR_WM) && (f != SCR_EM)) /* Always update warnings & errors */
  1045.       if (!displa || quiet || backgrd || fdispla == XYFD_N ||
  1046.       (server && !srvdis))
  1047.     return;
  1048.  
  1049. #ifdef CK_CURSES
  1050.     if (fdispla == XYFD_C) {        /* If fullscreen display selected */
  1051.     screenc(f,c,n,s);        /* call the fullscreen version */
  1052.     return;
  1053.     }
  1054. #endif /* CK_CURSES */
  1055.  
  1056.     len = (int)strlen(s);        /* Length of string */
  1057.  
  1058.     switch (f) {            /* Handle our function code */
  1059.  
  1060. case SCR_FN:                /* Filename */
  1061. #ifdef MAC
  1062.     conoll(""); conol(s); conoc(SP); hpos = len + 1;
  1063. #else
  1064.     strncpy(fbuf,s,80);
  1065.     newdpy = 1;                /* New file so refresh display */
  1066. #endif /* MAC */
  1067.     return;
  1068.  
  1069. case SCR_AN:                /* As-name */
  1070. #ifdef MAC
  1071.     if (hpos + len > 75) { conoll(""); hpos = 0; }
  1072.     conol("=> "); conol(s);
  1073.     if ((hpos += (len + 3)) > 78) { conoll(""); hpos = 0; }
  1074. #else
  1075.     strncpy(abuf,s,80);
  1076. #endif /* MAC */
  1077.     return;
  1078.  
  1079. case SCR_FS:                 /* File-size */
  1080. #ifdef MAC
  1081.     sprintf(buf,", Size: %ld",n);  conoll(buf);  hpos = 0;
  1082. #endif /* MAC */
  1083.     return;
  1084.  
  1085. case SCR_XD:                /* X-packet data */
  1086. #ifdef MAC
  1087.     conoll(""); conoll(s); hpos = 0;
  1088. #else
  1089.     strncpy(fbuf,s,80);
  1090. #endif /* MAC */
  1091.     return;
  1092.  
  1093. case SCR_ST:                  /* File status */
  1094.     switch (c) {
  1095.       case ST_OK:                  /* Transferred OK */
  1096.     showpkt('Z');            /* Update numbers one last time */
  1097.     if ((hpos += 5) > 78) conoll(""); /* Wrap screen line if necessary. */
  1098.     conoll(" [OK]"); hpos = 0;    /* Print OK message. */
  1099.     if (fdispla == XYFD_S) {    /* We didn't show Z packet when */
  1100.         conoc('Z');            /* it came, so show it now. */
  1101.         hpos = 1;
  1102.     }
  1103.     return;          
  1104.  
  1105.       case ST_DISC:             /*  Discarded */
  1106.     if ((hpos += 12) > 78) conoll("");
  1107.     conoll(" [discarded]"); hpos = 0;
  1108.     return;
  1109.  
  1110.       case ST_INT:               /*  Interrupted */
  1111.     if ((hpos += 14) > 78) conoll("");
  1112.     conoll(" [interrupted]"); hpos = 0;
  1113.     return;
  1114.  
  1115.       case ST_SKIP:             /*  Skipped */
  1116.     if ((hpos += 10) > 78) conoll("");
  1117.     conol(" [skipped]"); hpos = 0;
  1118.     return;
  1119.  
  1120.       case ST_ERR:            /* Error */
  1121.     conoll("");
  1122.     conol("Error: "); conoll(s); hpos = 0;
  1123.     return;
  1124.  
  1125.       case ST_REFU:            /* Refused */
  1126.     conoll("");
  1127.     conol("Refused: "); conoll(s); hpos = 0;
  1128.     return;
  1129.  
  1130.       case ST_INC:               /* Incomplete */
  1131.     if ((hpos += 12) > 78) conoll("");
  1132.     conoll(" [incomplete]"); hpos = 0;
  1133.     return;
  1134.  
  1135.       default:
  1136.     conoll("*** screen() called with bad status ***");
  1137.     hpos = 0;
  1138.     return;
  1139.     }
  1140.  
  1141. #ifdef MAC
  1142. case SCR_PN:                /* Packet number */
  1143.     sprintf(buf,"%s: %ld",s,n); conol(buf); hpos += (int)strlen(buf); return;
  1144. #endif /* MAC */
  1145.  
  1146. case SCR_PT:                /* Packet type or pseudotype */
  1147.     if (c == 'Y') return;        /* Don't bother with ACKs */
  1148.     if (c == 'D') {            /* In data transfer phase, */
  1149.     showpkt(NUL);            /* show progress. */
  1150.     return;
  1151.     }
  1152. #ifndef AMIGA
  1153.     if (hpos++ > 77) {            /* If near right margin, */
  1154.     conoll("");            /* Start new line */
  1155.     hpos = 0;            /* and reset counter. */
  1156.     }
  1157. #endif /* AMIGA */
  1158.     if (c == 'Z' && fdispla == XYFD_S)
  1159.       return;
  1160.     else
  1161.       conoc(c);                /* Display the packet type. */
  1162. #ifdef AMIGA
  1163.     if (c == 'G') conoll("");           /* New line after G packets */
  1164. #endif /* AMIGA */
  1165.     return;
  1166.  
  1167. case SCR_TC:                /* Transaction complete */
  1168.     conoc(BEL); conoll(""); return;
  1169.  
  1170. case SCR_EM:                /* Error message */
  1171.     conoll(""); conoc('?'); conoll(s); hpos = 0; return;
  1172.  
  1173. case SCR_WM:                /* Warning message */
  1174.     conoll(""); conoll(s); hpos = 0; return;
  1175.  
  1176. case SCR_TU:                /* Undelimited text */
  1177.     if ((hpos += len) > 77) { conoll(""); hpos = len; }
  1178.     conol(s); return;
  1179.  
  1180. case SCR_TN:                /* Text delimited at beginning */
  1181.     conoll(""); conol(s); hpos = len; return;
  1182.  
  1183. case SCR_TZ:                /* Text delimited at end */
  1184.     if ((hpos += len) > 77) { conoll(""); hpos = len; }
  1185.     conoll(s); return;
  1186.  
  1187. case SCR_QE:                /* Quantity equals */
  1188.     sprintf(buf,"%s: %ld",s,n);
  1189.     conoll(buf); hpos = 0; return;
  1190.  
  1191. case SCR_CW:                /* Close fullscreen window */
  1192.     return;                /* No window to close */
  1193.  
  1194. case SCR_CD:
  1195.     return;
  1196.  
  1197. default:
  1198.     conoll("*** screen() called with bad object ***");
  1199.     hpos = 0;
  1200.     return;
  1201.     }
  1202. }
  1203.  
  1204. /*  E R M S G  --  Nonfatal error message  */
  1205.  
  1206. /* Should be used only for printing the message text from an Error packet. */
  1207.  
  1208. VOID
  1209. ermsg(msg) char *msg; {            /* Print error message */
  1210.     if (local)
  1211.       screen(SCR_EM,0,0L,msg);
  1212.     tlog(F110,"Protocol Error:",msg,0L);
  1213. }
  1214.  
  1215. VOID
  1216. doclean() {                /* General cleanup upon exit */
  1217. #ifndef NOICP
  1218. #ifndef NOSPL
  1219.     extern struct mtab *mactab;        /* For ON_EXIT macro. */
  1220.     extern int nmac;
  1221. #endif /* NOSPL */
  1222. #endif /* NOICP */
  1223.  
  1224. #ifdef DEBUG
  1225.     if (deblog) {            /* Close any open logs. */
  1226.     debug(F100,"Debug Log Closed","",0);
  1227.     *debfil = '\0';
  1228.     deblog = 0;
  1229.     zclose(ZDFILE);
  1230.     }
  1231. #endif /* DEBUG */
  1232.     if (pktlog) {
  1233.     *pktfil = '\0';
  1234.     pktlog = 0;
  1235.     zclose(ZPFILE);
  1236.     }
  1237.     if (seslog) {
  1238.         *sesfil = '\0';
  1239.     seslog = 0;
  1240.     zclose(ZSFILE);
  1241.     }
  1242. #ifdef TLOG
  1243.     if (tralog) {
  1244.     tlog(F100,"Transaction Log Closed","",0L);
  1245.     *trafil = '\0';
  1246.     tralog = 0;
  1247.     zclose(ZTFILE);
  1248.     }
  1249. #endif /* TLOG */
  1250.  
  1251. #ifndef NOICP
  1252. #ifndef NOSPL
  1253.     zclose(ZRFILE);            /* READ and WRITE files, if any. */
  1254.     zclose(ZWFILE);
  1255. #ifndef NODIAL
  1256.     if (dialfd) fclose(dialfd);        /* Dial directory, if any. */
  1257. #endif /* NODIAL */
  1258. /*
  1259.   If a macro named "on_exit" is defined, execute it.  Also remove it from the
  1260.   macro table, in case its definition includes an EXIT or QUIT command, which
  1261.   would cause much recursion and would prevent the program from ever actually
  1262.   EXITing.
  1263. */
  1264.     if (nmac) {                /* Any macros defined? */
  1265.     int k;                /* Yes */
  1266.     k = mlook(mactab,"on_exit",nmac); /* Look up "on_exit" */
  1267.     if (k >= 0) {            /* If found, */
  1268.         *(mactab[k].kwd) = NUL;    /* poke its name from the table, */
  1269.         if (dodo(k,"") > -1)    /* set it up, */
  1270.           parser(1);        /* and execute it */
  1271.         }
  1272.     }
  1273. #endif /* NOSPL */
  1274. #endif /* NOICP */
  1275.  
  1276. /*
  1277.   Put console terminal back to normal.  This is done here because the
  1278.   ON_EXIT macro calls the parser, which meddles with console terminal modes.
  1279. */
  1280.     ttclos(0);                /* Close external line, if any */
  1281.     if (local) {
  1282.     strcpy(ttname,dftty);        /* Restore default tty */
  1283.     local = dfloc;            /* And default remote/local status */
  1284.     }
  1285.     conres();                /* Restore console terminal. */
  1286.  
  1287. #ifdef COMMENT
  1288. /* Should be no need for this, and maybe it's screwing things up? */
  1289.     connoi();                /* Turn off console interrupt traps */
  1290. #endif /* COMMENT */
  1291.  
  1292.     syscleanup();            /* System-dependent cleanup, last */
  1293. }
  1294.  
  1295. /*  D O E X I T  --  Exit from the program.  */
  1296.  
  1297. /*
  1298.   First arg is general, system-independent symbol: GOOD_EXIT or BAD_EXIT.
  1299.   If second arg is -1, take 1st arg literally.
  1300.   If second arg is not -1, work it into the exit code.
  1301. */
  1302. VOID
  1303. doexit(exitstat,what) int exitstat, what; {
  1304. #ifdef VMS
  1305.     char envstr[64];
  1306.     static $DESCRIPTOR(symnam,"CKERMIT_STATUS");
  1307.     static struct dsc$descriptor_s symval;
  1308.     int i;
  1309. #endif /* VMS */
  1310.  
  1311.     debug(F101,"doexit exitstat","",exitstat);
  1312.     debug(F101,"doexit what","",what);
  1313.  
  1314.     doclean();                /* First, clean up everything */
  1315.  
  1316. #ifdef VMS
  1317.     if (what == -1)
  1318.     what = 0;            /* Since we set two different items */
  1319.     sprintf(envstr,"%d", exitstat | what);
  1320.     symval.dsc$w_length = (int)strlen(envstr);
  1321.     symval.dsc$a_pointer = envstr;
  1322.     symval.dsc$b_class = DSC$K_CLASS_S;
  1323.     symval.dsc$b_dtype = DSC$K_DTYPE_T;
  1324.     i = 2;                /* Store in global table */
  1325.     LIB$SET_SYMBOL(&symnam, &symval, &i);
  1326.     if (exitstat == BAD_EXIT)
  1327.     exitstat = SS$_ABORT | STS$M_INHIB_MSG;
  1328.     if (exitstat == GOOD_EXIT)
  1329.     exitstat = SS$_NORMAL | STS$M_INHIB_MSG;
  1330.     exit(exitstat);
  1331. #else /* Not VMS */
  1332.     if (what == -1)            /* Take 1st arg literally */
  1333.       exit(exitstat);            /* e.g. user-supplied exit code */
  1334.     else                /* otherwise */
  1335.       exit(exitstat | what);        /* OR in the bits */
  1336. #endif /* VMS */
  1337. }
  1338.  
  1339. /* Set up interrupts */
  1340.  
  1341. VOID
  1342. setint() {
  1343.     conint(trap,stptrap);       /* Turn on console terminal interrupts. */
  1344.     bgchk();                    /* Check background status */
  1345. }
  1346.  
  1347. VOID
  1348. bgchk() {                /* Check background status */
  1349.     if (bgset < 0)
  1350.       pflag = !backgrd;            /* Set prompt flag */
  1351.     else                /* based on foreground/background */
  1352.       pflag = (bgset == 0 ? 1 : 0);
  1353.  
  1354.     /* Message flag on only if at top level, pflag is on, and QUIET is OFF */
  1355.  
  1356.     if (
  1357. #ifndef NOSPL
  1358.     cmdlvl == 0
  1359. #else
  1360.     tlevel < 0
  1361. #endif /* NOSPL */
  1362.     )
  1363.       msgflg = (pflag == 0) ? 0 : !quiet;
  1364.     else msgflg = 0;
  1365. }
  1366.  
  1367. #ifdef DEBUG
  1368. /*  D E B U G  --  Enter a record in the debugging log  */
  1369.  
  1370. /*
  1371.  Call with a format, two strings, and a number:
  1372.    f  - Format, a bit string in range 0-7.
  1373.         If bit x is on, then argument number x is printed.
  1374.    s1 - String, argument number 1.  If selected, printed as is.
  1375.    s2 - String, argument number 2.  If selected, printed in brackets.
  1376.    n  - Int, argument 3.  If selected, printed preceded by equals sign.
  1377.  
  1378.    f=0 is special: print s1,s2, and interpret n as a char.
  1379. */
  1380. #define DBUFL 2300
  1381. static char *dbptr = (char *)0;
  1382.  
  1383. int
  1384. dodebug(f,s1,s2,n) int f; char *s1, *s2; long n; {
  1385.     char *sp;
  1386.  
  1387.     if (!deblog) return(0);    /* If no debug log, don't. */
  1388.     if (!dbptr) {
  1389.     dbptr = malloc(DBUFL+1);
  1390.     if (!dbptr)
  1391.       return(0);
  1392.     }
  1393.     sp = dbptr;
  1394.     if (!s1) s1="(NULL)";
  1395.     if (!s2) s2="(NULL)";
  1396.     switch (f) {
  1397.         case F000:        /* 0, print both strings, and n as a char */
  1398.         if ((int)strlen(s1) + (int)strlen(s2) + 5 > DBUFL) {
  1399.         sprintf(sp,"DEBUG string too long\n");
  1400.         } else {
  1401.         if (n > 31 && n < 127)
  1402.           sprintf(sp,"%s%s:%c\n",s1,s2,(CHAR) n);
  1403.         else if (n < 32 || n == 127)
  1404.           sprintf(sp,"%s%s:^%c\n",s1,s2,(CHAR) ((n+64) & 0x7F));
  1405.         else if (n > 127 && n < 160)
  1406.           sprintf(sp,"%s%s:~^%c\n",s1,s2,(CHAR)((n-64) & 0x7F));
  1407.         else if (n > 159 && n < 256)
  1408.           sprintf(sp,"%s%s:~%c\n",s1,s2,(CHAR) (n & 0x7F));
  1409.         else sprintf(sp,"%s%s:%ld\n",s1,s2,n);
  1410.         }
  1411.         if (zsout(ZDFILE,dbptr) < 0) deblog = 0;
  1412.         break;
  1413.         case F001:            /* 1, "=n" */
  1414.         sprintf(sp,"=%ld\n",n);
  1415.         if (zsout(ZDFILE,dbptr) < 0) deblog = 0;
  1416.         break;
  1417.         case F010:            /* 2, "[s2]" */
  1418.         if ((int)strlen(s2) + 4 > DBUFL)
  1419.           sprintf(sp,"DEBUG string too long\n");
  1420.         else sprintf(sp,"[%s]\n",s2);
  1421.         if (zsout(ZDFILE,"") < 0) deblog = 0;
  1422.         break;
  1423.         case F011:            /* 3, "[s2]=n" */
  1424.         if ((int)strlen(s2) + 15 > DBUFL)
  1425.           sprintf(sp,"DEBUG string too long\n");
  1426.         else sprintf(sp,"[%s]=%ld\n",s2,n);
  1427.         if (zsout(ZDFILE,dbptr) < 0) deblog = 0;
  1428.         break;
  1429.         case F100:            /* 4, "s1" */
  1430.         if (zsoutl(ZDFILE,s1) < 0) deblog = 0;
  1431.         break;
  1432.         case F101:            /* 5, "s1=n" */
  1433.         if ((int)strlen(s1) + 15 > DBUFL)
  1434.           sprintf(sp,"DEBUG string too long\n");
  1435.         else sprintf(sp,"%s=%ld\n",s1,n);
  1436.         if (zsout(ZDFILE,dbptr) < 0) deblog = 0;
  1437.         break;
  1438.         case F110:            /* 6, "s1[s2]" */
  1439.         if ((int)strlen(s1) + (int)strlen(s2) + 4 > DBUFL)
  1440.           sprintf(sp,"DEBUG string too long\n");
  1441.         else sprintf(sp,"%s[%s]\n",s1,s2);
  1442.         if (zsout(ZDFILE,dbptr) < 0) deblog = 0;
  1443.         break;
  1444.         case F111:            /* 7, "s1[s2]=n" */
  1445.         if ((int)strlen(s1) + (int)strlen(s2) + 15 > DBUFL)
  1446.           sprintf(sp,"DEBUG string too long\n");
  1447.         else sprintf(sp,"%s[%s]=%ld\n",s1,s2,n);
  1448.         if (zsout(ZDFILE,dbptr) < 0) deblog = 0;
  1449.         break;
  1450.     default:
  1451.         sprintf(sp,"\n?Invalid format for debug() - %d\n",f);
  1452.         if (zsout(ZDFILE,dbptr) < 0) deblog = 0;
  1453.     }
  1454.     return(0);
  1455. }
  1456. #endif /* DEBUG */
  1457.  
  1458. #ifdef TLOG
  1459. #define TBUFL 300
  1460. /*  T L O G  --  Log a record in the transaction file  */
  1461. /*
  1462.  Call with a format and 3 arguments: two strings and a number:
  1463.    f  - Format, a bit string in range 0-7, bit x is on, arg #x is printed.
  1464.    s1,s2 - String arguments 1 and 2.
  1465.    n  - Int, argument 3.
  1466. */
  1467. VOID
  1468. tlog(f,s1,s2,n) int f; long n; char *s1, *s2; {
  1469.     static char s[TBUFL];
  1470.     char *sp = s; int x;
  1471.  
  1472.     if (!tralog) return;        /* If no transaction log, don't */
  1473.     switch (f) {
  1474.         case F000:            /* 0 (special) "s1 n s2"  */
  1475.         if ((int)strlen(s1) + (int)strlen(s2) + 15 > TBUFL)
  1476.           sprintf(sp,"?T-Log string too long\n");
  1477.         else sprintf(sp,"%s %ld %s\n",s1,n,s2);
  1478.         if (zsout(ZTFILE,s) < 0) tralog = 0;
  1479.         break;
  1480.         case F001:            /* 1, " n" */
  1481.         sprintf(sp," %ld\n",n);
  1482.         if (zsout(ZTFILE,s) < 0) tralog = 0;
  1483.         break;
  1484.         case F010:            /* 2, "[s2]" */
  1485.         x = (int)strlen(s2);
  1486.         if (s2[x] == '\n') s2[x] = '\0';
  1487.         if (x + 6 > TBUFL)
  1488.           sprintf(sp,"?T-Log string too long\n");
  1489.         else sprintf(sp,"[%s]\n",s2);
  1490.         if (zsout(ZTFILE,"") < 0) tralog = 0;
  1491.         break;
  1492.         case F011:            /* 3, "[s2] n" */
  1493.         x = (int)strlen(s2);
  1494.         if (s2[x] == '\n') s2[x] = '\0';
  1495.         if (x + 6 > TBUFL)
  1496.           sprintf(sp,"?T-Log string too long\n");
  1497.         else sprintf(sp,"[%s] %ld\n",s2,n);
  1498.         if (zsout(ZTFILE,s) < 0) tralog = 0;
  1499.         break;
  1500.         case F100:            /* 4, "s1" */
  1501.         if (zsoutl(ZTFILE,s1) < 0) tralog = 0;
  1502.         break;
  1503.         case F101:            /* 5, "s1: n" */
  1504.         if ((int)strlen(s1) + 15 > TBUFL)
  1505.           sprintf(sp,"?T-Log string too long\n");
  1506.         else sprintf(sp,"%s: %ld\n",s1,n);
  1507.         if (zsout(ZTFILE,s) < 0) tralog = 0;
  1508.         break;
  1509.         case F110:            /* 6, "s1 s2" */
  1510.         x = (int)strlen(s2);
  1511.         if (s2[x] == '\n') s2[x] = '\0';
  1512.         if ((int)strlen(s1) + x + 4 > TBUFL)
  1513.           sprintf(sp,"?T-Log string too long\n");
  1514.         else sprintf(sp,"%s %s\n",s1,s2);
  1515.         if (zsout(ZTFILE,s) < 0) tralog = 0;
  1516.         break;
  1517.         case F111:            /* 7, "s1 s2: n" */
  1518.         x = (int)strlen(s2);
  1519.         if (s2[x] == '\n') s2[x] = '\0';
  1520.         if ((int)strlen(s1) + x + 15 > TBUFL)
  1521.           sprintf(sp,"?T-Log string too long\n");
  1522.         else sprintf(sp,"%s %s: %ld\n",s1,s2,n);
  1523.         if (zsout(ZTFILE,s) < 0) tralog = 0;
  1524.         break;
  1525.     default:
  1526.         sprintf(sp,"\n?Invalid format for tlog() - %ld\n",n);
  1527.         if (zsout(ZTFILE,s) < 0) tralog = 0;
  1528.     }
  1529. }
  1530. #endif /* TLOG */
  1531.  
  1532. #ifdef CK_CURSES
  1533.  
  1534. /*
  1535.   There are three different ways to do fullscreen on VMS.
  1536.   1. Use the real curses library, VAXCCURSE.
  1537.   2. Use do-it-yourself code.
  1538.   3. Use the Screen Manager, SMG$.
  1539.  
  1540.   Method 1 doesn't work quite right; you can't call endwin(), so once you've
  1541.   started curses mode, you can never leave.
  1542.  
  1543.   Method 2 doesn't optimize the screen, and so much more time is spent in
  1544.   screen writes.  This actually causes file transfers to fail because the
  1545.   tty device input buffer can be overrun while the screen is being updated,
  1546.   especially on a slow MicroVAX that has small typeahead buffers.
  1547.  
  1548.   In the following #ifdef block, #define one of them and #undef the other 2.
  1549.  
  1550.   So now let's try method 3...
  1551. */
  1552. #ifdef VMS
  1553. #define CK_SMG                /* Screen Manager */
  1554. #undef MYCURSES                /* Do-it-yourself */
  1555. #undef VMSCURSE                /* VAXCCURSE library */
  1556. #endif /* VMS */
  1557.  
  1558. /*  S C R E E N C  --  Screen display function, uses curses  */
  1559.  
  1560. /* Idea for curses display contributed by Chris Pratt of APV Baker, UK */
  1561.  
  1562. /* Avoid conficts with curses.h */
  1563.  
  1564. #ifndef MYCURSES
  1565. #undef VOID                /* This was defined in ckcdeb.h */
  1566. #endif /* MYCURSES */
  1567.  
  1568. #undef BS                /* These were defined in ckcasc.h */
  1569. #undef CR
  1570. #undef NL
  1571. #undef SO
  1572. #undef US
  1573.  
  1574. #ifdef VMS                /* VMS fullscreen display */
  1575. #ifdef MYCURSES                /* Do-it-yourself method */
  1576. extern int isvt52;            /* From CKVTIO.C */
  1577. #define printw printf
  1578. #else
  1579. #ifdef VMSCURSE                /* VMS curses library VAXCCURSE */
  1580. #include <curses.h> 
  1581. /* Note: Screen manager doesn't need a header file */
  1582. #endif /* VMSCURSE */
  1583. #endif /* MYCURSES */
  1584. #else                    /* Not VMS */
  1585. #ifdef MYCURSES                /* Do-it-yourself method */
  1586. #define isvt52 0            /* Used by OS/2, VT-100/ANSI always */
  1587. #define printw printf
  1588. #else
  1589. #include <curses.h>            /* So use real curses */
  1590. #endif /* MYCURSES */
  1591. #endif /* VMS */
  1592.  
  1593. #ifdef CK_SMG
  1594. /*
  1595.   Long section for Screen Manager starts here...
  1596.   By William Bader.
  1597. */
  1598. #include "ckvvms.h"
  1599. /* #include <smgdef.h> */
  1600. /* #include <smgmsg.h> */
  1601.  
  1602. extern unsigned int vms_status;        /* Used for system service return status */
  1603.  
  1604. static long smg_pasteboard_id = -1;    /* pasteboard identifier */
  1605. static long smg_display_id = -1;    /* display identifier */
  1606. static int smg_open = 0;        /* flag if smg current open */
  1607.  
  1608. #define    clrtoeol()    SMG$ERASE_LINE(&smg_display_id, 0, 0)
  1609.  
  1610. #define clear()        SMG$ERASE_DISPLAY(&smg_display_id, 0, 0, 0, 0)
  1611.  
  1612. #define    touchwin(scr)    SMG$REPAINT_SCREEN(&smg_pasteboard_id)
  1613.  
  1614. static void
  1615. move(row, col) int row, col; {
  1616.     /* Change from 0-based for curses to 1-based for SMG */
  1617.     ++row; ++col;
  1618.     CHECK_ERR("move: smg$set_cursor_abs",
  1619.           SMG$SET_CURSOR_ABS(&smg_display_id, &row, &col));
  1620. }
  1621.  
  1622. static void
  1623. refresh() {
  1624.     CHECK_ERR("refresh: smg$end_pasteboard_update",
  1625.           SMG$END_PASTEBOARD_UPDATE(&smg_pasteboard_id));
  1626.     CHECK_ERR("refresh: smg$begin_pasteboard_update",
  1627.           SMG$BEGIN_PASTEBOARD_UPDATE(&smg_pasteboard_id));
  1628. }
  1629.  
  1630. #ifdef VMS_V40
  1631. #define    OLD_VMS
  1632. #endif /* VMS_V40 */
  1633. #ifdef VMS_V42
  1634. #define    OLD_VMS
  1635. #endif /* VMS_V42 */
  1636. #ifdef VMS_V44
  1637. #define    OLD_VMS
  1638. #endif /* VMS_V44 */
  1639.  
  1640. static int
  1641. initscr() {
  1642.     int rows = 24, cols = 80;
  1643.     int row = 1, col = 1;
  1644.  
  1645.     if (smg_pasteboard_id == -1) {     /* Open the screen */
  1646. #ifdef OLD_VMS
  1647.     CHECK_ERR("initscr: smg$create_pasteboard",
  1648.           SMG$CREATE_PASTEBOARD(&smg_pasteboard_id, 0, 0, 0, 0));
  1649. #else
  1650.     /* For VMS V5, not tested */
  1651.     CHECK_ERR("initscr: smg$create_pasteboard",
  1652.           SMG$CREATE_PASTEBOARD(&smg_pasteboard_id, 0, 0, 0, 0, 0));
  1653. #endif /* OLD_VMS */
  1654.     }
  1655.  
  1656.     if (smg_display_id == -1) {        /* Create a display window */
  1657.  
  1658.     CHECK_ERR("initscr: smg$create_virtual_display",
  1659.           SMG$CREATE_VIRTUAL_DISPLAY(&rows, &cols, &smg_display_id,
  1660.                          0, 0, 0));
  1661.  
  1662.     /* Connect the display window to the screen */
  1663.     CHECK_ERR("initscr: smg$paste_virtual_display",
  1664.           SMG$PASTE_VIRTUAL_DISPLAY(&smg_display_id,&smg_pasteboard_id,
  1665.                         &row,&col));
  1666.     }
  1667.  
  1668.     if (!smg_open) {            /* Start a batch update */
  1669.     smg_open = 1;
  1670.     CHECK_ERR("initscr: smg$begin_pasteboard_update",
  1671.           SMG$BEGIN_PASTEBOARD_UPDATE(&smg_pasteboard_id));
  1672.     }
  1673.     return(1);
  1674. }
  1675.  
  1676. static void
  1677. endwin() {
  1678.     if (!smg_open)
  1679.       return;
  1680.  
  1681.     smg_open = 0;
  1682.  
  1683.     CHECK_ERR("endwin: smg$end_pasteboard_update",
  1684.           SMG$END_PASTEBOARD_UPDATE(&smg_pasteboard_id));
  1685.  
  1686.     move(22, 0);
  1687.  
  1688. #ifdef COMMENT
  1689. /*
  1690.   These calls clear the screen.
  1691. */
  1692.     CHECK_ERR("endwin: smg$delete_virtual_display",
  1693.           SMG$DELETE_VIRTUAL_DISPLAY(&smg_display_id));
  1694.     smg_display_id = -1;
  1695.  
  1696.     CHECK_ERR("endwin: smg$delete_pasteboard",
  1697.           SMG$DELETE_PASTEBOARD(&smg_pasteboard_id, 0));
  1698.     smg_pasteboard_id = -1;
  1699. #endif /* COMMENT */
  1700. }
  1701.  
  1702. static void printw(str, a1, a2, a3, a4, a5, a6, a7, a8)
  1703. char *str;
  1704. long a1, a2, a3, a4, a5, a6, a7, a8;
  1705. /* printw */ {
  1706.     char buf[255];
  1707.     $DESCRIPTOR(text_dsc, buf);
  1708.  
  1709.     text_dsc.dsc$w_length = sprintf(buf, str, a1, a2, a3, a4, a5, a6, a7, a8);
  1710.     CHECK_ERR("printw: smg$put_chars",
  1711.           SMG$PUT_CHARS(&smg_display_id, &text_dsc, 0, 0, 0, 0, 0));
  1712. }
  1713. #endif /* CK_SMG */
  1714.  
  1715. #ifdef MYCURSES
  1716. /*
  1717.   Do-it-yourself curses implementation for VMS, OS/2 and other ANSI/VT-100's.
  1718.   Supports only the VT52 and VT1xx (and later VT2xx/3xx/4xx) terminals.
  1719.   By Terry Kennedy, St Peters College.
  1720.  
  1721.   First, some stuff we can just ignore:
  1722. */
  1723.  
  1724. int
  1725. touchwin(x) int x; {
  1726. }
  1727. int
  1728. initscr() {
  1729. }
  1730. int
  1731. refresh() {
  1732. }
  1733. int
  1734. endwin() {
  1735. }
  1736.  
  1737. /*
  1738.  * Now, some stuff we need to do:
  1739.  */
  1740.  
  1741. _PROTOTYP( int move, (int, int) );
  1742.  
  1743. int
  1744. move(row, col) int row, col; {
  1745.     if (isvt52)
  1746.       printf("\033Y%c%c", row + 037, col + 037);
  1747.     else
  1748.       printf("\033[%d;%dH", row + 1, col + 1);
  1749. }
  1750.  
  1751. int
  1752. clear() {
  1753.     move(1,1);
  1754.     if (isvt52)
  1755.       printf("\033J");
  1756.     else
  1757.       printf("\033[J");
  1758. }
  1759.  
  1760. int
  1761. clrtoeol() {
  1762.     if (isvt52)
  1763.       printf("\033K");
  1764.     else
  1765.       printf("\033[K");
  1766. }
  1767. #endif /* MYCURSES */
  1768.  
  1769. /* Screen line numbers */
  1770.  
  1771. #define CW_BAN  0            /* Curses Window Banner */
  1772. #define CW_DIR  2            /* Current directory */
  1773. #define CW_LIN  3            /* Communication device */
  1774. #define CW_SPD  4            /* Communication speed */
  1775. #define CW_PAR  5            /* Parity */
  1776. #define CW_NAM  7            /* Filename */
  1777. #define CW_TYP  8            /* File type */
  1778. #define CW_SIZ  9            /* File size */
  1779. #define CW_PCD 10            /* Percent done */
  1780. #define CW_TR  11            /* Time remaining */
  1781. #define CW_WS  12            /* Window slots */
  1782. #define CW_PT  13            /* Packet type */
  1783. #define CW_PC  14            /* Packet count */
  1784. #define CW_PL  15            /* Packet length */
  1785. #define CW_PR  16            /* Packet retry */
  1786. #define CW_PB  17            /* Packet block check */
  1787. #define CW_ERR 19            /* Error message */
  1788. #define CW_MSG 20            /* Info message */
  1789. #define CW_INT 22            /* Instructions */
  1790.  
  1791. static int cinit = 0;            /* Flag for curses init'd */
  1792. static int cendw = 0;            /* endwin() was called */
  1793.  
  1794. static
  1795. #ifdef CK_ANSIC                /* Because VOID used by curses.h */
  1796. void
  1797. #else
  1798. #ifdef MYCURSES
  1799. VOID
  1800. #else
  1801. int
  1802. #endif /* MYCURSES */
  1803. #endif /* CK_ANSIC */
  1804. scrft() {                /* Display file type */
  1805.     move(CW_TYP,22);
  1806.     if (binary) {
  1807. #ifdef VMS
  1808.     if (binary == XYFT_I)
  1809.       printw("image");
  1810.     else if (binary == XYFT_L)
  1811.       printw("labeled");
  1812.     else printw("binary");
  1813. #else /* Not VMS */
  1814.     printw("binary");
  1815. #endif /* VMS */
  1816.     } else {
  1817.     printw("text");
  1818. #ifndef NOCSETS
  1819.     if (tcharset == TC_TRANSP) {
  1820.         printw(" (transparent)");
  1821.     } else {
  1822.         if (what == W_SEND)
  1823.           printw(" (%s => %s)",
  1824.              fcsinfo[fcharset].keyword,
  1825.              tcsinfo[tcharset].keyword);
  1826.         else printw(" (%s => %s)",
  1827.              tcsinfo[tcharset].keyword,
  1828.              fcsinfo[fcharset].keyword);
  1829.     }
  1830. #endif /* NOCSETS */
  1831.     }
  1832.     clrtoeol();
  1833.     return;
  1834. }
  1835.  
  1836. char *                    /* Convert seconds to hh:mm:ss */
  1837. #ifdef CK_ANSIC
  1838. hhmmss(long x)
  1839. #else
  1840. hhmmss(x) long x;
  1841. #endif /* CK_ANSIC */
  1842. /* hhmmss(x) */ {
  1843.     static char buf[10];
  1844.     long s, h, m;
  1845.     h = x / 3600L;            /* Hours */
  1846.     x = x % 3600L;
  1847.     m = x / 60L;            /* Minutes */
  1848.     s = x % 60L;            /* Seconds */
  1849.     if (x > -1L)
  1850.       sprintf(buf,"%02ld:%02ld:%02ld",h,m,s);
  1851.     else buf[0] = NUL;
  1852.     return((char *)buf);
  1853. }
  1854.  
  1855. #ifdef CK_NEWTERM
  1856. static FILE *ck_stdout = NULL;
  1857. static int ck_fd = -1;
  1858. #endif /* CK_NEWTERM */
  1859.  
  1860. static long pct = 100, oldpct = 0;    /* Percent done */
  1861. static int oldtyp = 0, oldwin = -1, oldtry = -1, oldlen = -1;
  1862.  
  1863. #ifdef CK_ANSIC
  1864. void
  1865. screenc(int f, char c,long n,char *s)
  1866. #else
  1867. #ifdef MYCURSES
  1868. VOID
  1869. #else
  1870. int
  1871. #endif /* MYCURSES */
  1872. screenc(f,c,n,s)
  1873. int f;        /* argument descriptor */
  1874. char c;        /* a character or small integer */
  1875. long n;        /* a long integer */
  1876. char *s;    /* a string */
  1877. #endif /* CK_ANSIC */
  1878. /* screenc() */ {
  1879.  
  1880.     static int q = 0;
  1881.     static long fsiz = -1L;        /* Copy of file size */
  1882.     static long fcnt = 0L;        /* File count */
  1883.     static long fbyt = 0L;        /* Total file bytes */
  1884.  
  1885.     int len;                /* Length of string */
  1886.     int x;                /* Worker */
  1887.  
  1888.     if (cinit == 0 || cendw > 0) {    /* Handle borderline cases... */
  1889.     if (f == SCR_CW) {        /* Close window, but it's not open */
  1890.         ft_win = 0;
  1891.         return;
  1892.     }
  1893.     if (f == SCR_EM ||
  1894.        (f == SCR_PT && c == 'E')) {    /* Fatal error before window open */
  1895.         conoll(""); conoc('?'); conoll(s); return; /* Regular display */
  1896.     }
  1897.     }
  1898.     if (cinit == 0) {            /* Only call initscr() once */
  1899.     cendw = 1;            /* New window needs repainting */
  1900. #ifdef COMMENT
  1901.     if (!initscr()) {        /* Oops, can't initialize window? */
  1902. /*
  1903.   In fact, this doesn't happen.  "man curses" says initscr() halts the
  1904.   entire program if it fails, which is true on the systems where I've
  1905.   tested it.  It will fail if your terminal type is not known to it.
  1906.   That's why SET FILE DISPLAY FULLSCREEN calls tgetent() to make sure the
  1907.   terminal type is known before allowing a curses display.
  1908. */
  1909.         fprintf(stderr,"CURSES INITSCR ERROR\r\n");
  1910.         fdispla = XYFD_R;        /* Go back to regular display */
  1911.         return;
  1912.     } else {
  1913.         cinit++;            /* Window initialized ok */
  1914.         debug(F100,"CURSES INITSCR OK","",0);
  1915.     }
  1916. #else                    /* Save some memory. */
  1917. #ifdef CK_NEWTERM
  1918.     /* (From Andy Fyfe <andy@vlsi.cs.caltech.edu>)
  1919.        System V curses seems to reserve the right to alter the buffering
  1920.        on the output FILE* without restoring it.  Fortunately System V
  1921.        curses provides newterm(), an alternative to initscr(), that
  1922.        allows us to specify explicitly the terminal type and input and
  1923.        output FILE pointers.  Thus we duplicate stdout, and let curses
  1924.        have the copy.  The original remains unaltered.  Unfortunately,
  1925.        newterm() seems to be particular to System V.
  1926.     */
  1927.     s = getenv("TERM");
  1928.     if (ck_fd < 0) {
  1929.         ck_fd = dup(fileno(stdout));
  1930.         ck_stdout = (ck_fd >= 0) ? fdopen(ck_fd, "w") : NULL;
  1931.     }
  1932.     if (ck_stdout == NULL || newterm(s, ck_stdout, stdin) == 0) {
  1933.         fprintf(stderr,
  1934.           "Fullscreen display not supported for terminal type: %s\r\n",s);
  1935.         fdispla = XYFD_R;        /* Go back to regular display */
  1936.         return;
  1937.     }
  1938. #else
  1939.     initscr();            /* Initialize curses. */
  1940. #endif /* CK_NEWTERM */
  1941.     cinit++;            /* Remember curses was initialized. */
  1942. #endif /* COMMENT */
  1943.     }
  1944.     ft_win = 1;                /* Window is open */
  1945.     if (cendw) {            /* endwin() was called previously */
  1946. #ifdef VMS
  1947.     initscr();            /* (or should have been!) */
  1948.     clear();
  1949.     touchwin(stdscr);
  1950.     refresh();
  1951. #else /* All others... */
  1952.     clear();
  1953. #endif /* VMS */
  1954.  
  1955.     move(CW_BAN,0);            /* Display the banner */
  1956.     if (*myhost) printw("%s, %s",versio,(char *)myhost);
  1957.     else printw("%s",versio);
  1958.     move(CW_DIR,3);  printw("Current Directory: %s",zgtdir());
  1959.     if (network) {
  1960.         move(CW_LIN,9); printw("Remote Host: %s",ttname);
  1961.     } else {
  1962.         move(CW_LIN,0);  printw("Communication Device: %s",ttname);
  1963.     }
  1964.     move(CW_SPD,1);  printw("Communication Speed: ");
  1965.     move(CW_SPD,22);        /* Speed */
  1966.     if (network) {
  1967.         printw("(network)");
  1968.     } else {
  1969.         if (speed < 0L) speed = ttgspd();
  1970.         if (speed > 0L) {
  1971.         if (speed == 8880) printw("75/1200");
  1972.         else printw("%ld",speed);
  1973.         } else printw("unknown");
  1974.     }
  1975.     move(CW_PAR,14); printw("Parity: %s",parnam((char)parity));
  1976.     move(CW_TYP,11); printw("File Type:");
  1977.     move(CW_SIZ,11); printw("File Size:");
  1978.     move(CW_PCD, 8); printw("Percent Done:");
  1979.     move(CW_TR,  1); printw("Estimated Time Left:");
  1980.     move(CW_WS,  8); printw("Window Slots:");
  1981.     move(CW_PT,  9); printw("Packet Type:");
  1982.     move(CW_PC,  8); printw("Packet Count:");
  1983.     move(CW_PL,  7); printw("Packet Length:");
  1984.     move(CW_PR,  2); printw("Packet Retry Count:");
  1985.     move(CW_PB,  2); printw("Packet Block Check:");
  1986.     move(CW_ERR,10); printw("Last Error:");
  1987.     move(CW_MSG, 8); printw("Last Message:");
  1988. #ifndef CK_POLL
  1989. #ifdef ATTSV
  1990. #ifndef aegis
  1991. #ifndef datageneral
  1992. #ifndef OXOS
  1993. #define CK_NEED_SIG
  1994. #endif /* OXOS */
  1995. #endif /* datageneral */
  1996. #endif /* aegis */
  1997. #endif /* ATTSV */
  1998. #ifdef POSIX
  1999. #ifndef CK_NEED_SIG
  2000. #define CK_NEED_SIG
  2001. #endif /* CK_NEED_SIG */
  2002. #endif /* POSIX */
  2003. #endif /* CK_POLL */
  2004.  
  2005. #ifdef BSD44
  2006. #ifdef CK_NEED_SIG
  2007. #undef CK_NEED_SIG
  2008. #endif /* CK_NEED_SIG */
  2009. #endif /* BSD44 */
  2010.  
  2011. #ifdef CK_NEED_SIG
  2012.     move(CW_INT, 0); printw(
  2013. "<%s>X to cancel file, <%s>Z to cancel group, <%s><CR> to resend packet",
  2014.                 dbchr(escape), dbchr(escape), dbchr(escape));
  2015.     move(CW_INT + 1, 0); printw(
  2016. "<%s>E to send Error packet, or Ctrl-C to quit immediately.", dbchr(escape));
  2017. #else
  2018.     move(CW_INT, 0);
  2019. #ifdef OS2
  2020.     printw(
  2021.       "X to cancel file, Z to cancel group, <Enter> to resend packet,");
  2022. #else
  2023.     printw("X to cancel file, Z to cancel group, <CR> to resend packet,");
  2024. #endif /* OS2 */
  2025.     move(CW_INT + 1, 0);
  2026.     printw("E to send Error packet, or Ctrl-C to quit immediately.");
  2027. #endif /* CK_NEED_SIG */
  2028.     refresh();
  2029.     cendw = 0;
  2030.     }
  2031.     len = strlen(s);            /* Length of argument string */
  2032.  
  2033.     debug(F101,"SCREENC switch","",f);    /* Handle our function code */
  2034.     switch (f) {
  2035.       case SCR_FN:                /* Filename */
  2036.     fsiz = -1L;            /* Invalidate previous file size */
  2037.     move(CW_PCD,22);        /* Erase percent done from last time */
  2038.     clrtoeol();
  2039.     move(CW_SIZ,22);        /* Erase file size from last time */
  2040.     clrtoeol();
  2041.     move(CW_ERR,22);        /* And last error message */
  2042.     clrtoeol();
  2043.     if (what == W_SEND) {        /* If we're sending... */
  2044.         move(CW_NAM,13);
  2045.         printw("Sending:");
  2046.     } else if (what == W_RECV) {    /* If we're receiving... */
  2047.         move(CW_NAM,11);
  2048.         printw("Receiving:");
  2049.     } else {            /* If we don't know... */
  2050.         move(CW_NAM,11);        /* (should never see this) */
  2051.         printw("File Name:");
  2052.     }
  2053.     move(CW_NAM,22);        /* Display the filename */
  2054.     if (len > 57) {
  2055.         printw("%.54s..",s);
  2056.         len = 57;
  2057.     } else printw("%s",s);
  2058.     q = len;            /* Remember name length for later */
  2059.     clrtoeol();
  2060.     scrft();            /* Display file type */
  2061.     refresh(); return;
  2062.  
  2063.       case SCR_AN:                /* File as-name */
  2064.     if (q + len < 58) {        /* Will fit */
  2065.         move(CW_NAM, 22 + q);
  2066.         printw(" => %s",s);
  2067.     } else {            /* Too long */
  2068.         move(CW_NAM, 22);        /* Overwrite previous name */
  2069.         q = 0;
  2070.         len = 54;
  2071.         printw(" => %.51s..", s);    /* Truncate */
  2072.     }
  2073.     q += len + 4;            /* Remember horizontal position */
  2074.     clrtoeol(); refresh(); return;
  2075.  
  2076.       case SCR_FS:             /* File size */
  2077.     fsiz = n;
  2078.     move(CW_SIZ,22);
  2079.     if (fsiz > -1L) printw("%ld",n);
  2080.     clrtoeol();
  2081.     scrft();            /* File type */
  2082.     refresh(); return;
  2083.  
  2084.       case SCR_PT:                /* Packet type or pseudotype */
  2085.     if (spackets < 5) {
  2086.         /* Things that won't change after the 4th packet */
  2087.         move(CW_PAR,22); printw("%s",parnam((char)parity)); clrtoeol();
  2088.         clrtoeol();
  2089.         move(CW_PB, 22);        /* Block check on this packet */
  2090.         if (bctu == 4) printw("B"); else printw("%d",bctu);
  2091.         clrtoeol();
  2092.     }
  2093.  
  2094.     x = (what == W_RECV) ?        /* Packet length */
  2095.       rpktl+1 :
  2096.         spktl+1;
  2097.     if (x != oldlen) {        /* But only if it changed. */
  2098.         move(CW_PL, 22);
  2099.         printw("%d",x);
  2100.         clrtoeol();
  2101.         oldlen = x;
  2102.     }
  2103.     move(CW_PC, 22);        /* Packet count (always). */
  2104.     printw("%d",spackets);        /* WARNING: this can slow us way */
  2105.     clrtoeol();            /* down with short packets. */
  2106.  
  2107.     if (wcur != oldwin) {        /* Window slots, if changed. */
  2108.         move(CW_WS, 22);
  2109.         printw("%d of %d",wcur,wslotr);
  2110.         clrtoeol();
  2111.         oldwin = wcur;
  2112.     }
  2113.     if (retrans != oldtry) {    /* Retry count, if changed */
  2114.         move(CW_PR, 22);
  2115.         printw("%d",retrans);
  2116.         clrtoeol();
  2117.         oldtry = retrans;
  2118.     }
  2119.     if (c != oldtyp && c != 'Y' && c != 'N') { /* Sender's packet type */
  2120.         move(CW_PT,22);
  2121.         printw("%c",c);
  2122.         clrtoeol();
  2123.         oldtyp = c;
  2124.     }
  2125.     switch (c) {            /* Now handle specific packet types */
  2126.       case 'S':            /* Beginning of transfer */
  2127.         fcnt = fbyt = 0L;        /* Clear counters */
  2128.         break;
  2129.       case 'D':            /* Data packet */
  2130.         if (fsiz > 0L) {        /* Show percent done if known */
  2131.         long s, x;
  2132.         oldpct = pct;        /* Remember previous percent */
  2133.         pct = (fsiz > 99L) ? (ffc / (fsiz / 100L)) : 0L; /* New one */
  2134.         if (pct > 100L ||    /* Allow expansion */
  2135.            (oldpct == 99L && pct < 0L)) /* other boundary conditions */
  2136.           pct = 100L;
  2137.         if (pct != oldpct) {    /* Only do this 100 times per file */
  2138.             move(CW_PCD,22);
  2139.             printw("%ld", pct);
  2140.             clrtoeol();
  2141.  
  2142.             /* Time remaining for this file */
  2143.  
  2144.             s = (long) ((unsigned) gtimer() - fsecs); /* Secs so far */
  2145.             if (s > 0L) {
  2146.             /*
  2147.               Time remaining must be calculated using the smallest
  2148.               possible quantities, to prevent overflow:
  2149.                 (seconds_so_far * percent_left) / percent_done.
  2150.               And avoid divide_by_zero.
  2151.             */
  2152.             x = (pct > 0L) ? ((s * (100 - pct)) / pct) : -1L;
  2153.             if (x > -1L) {
  2154.                 move(CW_TR,22);
  2155.                 printw("%s",hhmmss(x));
  2156.                 clrtoeol();
  2157.             }
  2158.             }
  2159.         }
  2160.         }
  2161.         break;
  2162.       case 'E':            /* Error packet */
  2163. #ifdef COMMENT
  2164.         move(CW_ERR,22);        /* Print its data field */
  2165.         if (*s) printw("%s",s);
  2166.         clrtoeol();
  2167. #endif /* COMMENT */
  2168.         fcnt = fbyt = 0;        /* So no bytes for this file */
  2169.         break;
  2170.       case 'Q':            /* Crunched packet */
  2171.         move(CW_ERR,22);
  2172.         printw("Damaged Packet");
  2173.         clrtoeol();
  2174.         break;
  2175.       case 'T':            /* Timeout */
  2176.         move(CW_ERR,22);
  2177.         printw("Timeout");
  2178.         clrtoeol();
  2179.         break;
  2180.       default:            /* Others, do nothing */
  2181.         break;
  2182.     }
  2183.     refresh(); return;
  2184.  
  2185.       case SCR_ST:            /* File transfer status */
  2186.     move(CW_PCD,22);        /* Update percent done */
  2187.     if (c == ST_OK) {        /* OK, print 100 % */
  2188.         pct = 100;
  2189.         printw("100");
  2190.     } else if (fsiz > 0L)        /* Not OK, update final percent */
  2191.       printw("%ld",( ffc * 100L ) / fsiz);
  2192.     clrtoeol();
  2193.     move(CW_MSG,22);        /* Remove any previous message */
  2194.     clrtoeol(); refresh();
  2195.     move(CW_TR, 22);
  2196.     clrtoeol(); refresh();
  2197.  
  2198.     switch (c) {            /* Print new status message */
  2199.       case ST_OK:            /* Transfer OK */
  2200.         fcnt++;            /* Count this file */
  2201.         fbyt += ffc;        /* Count its bytes */
  2202.         move(CW_MSG,22);
  2203.         printw("Transfer OK");    /* Say Transfer was OK */
  2204.         clrtoeol(); refresh();
  2205.         return;
  2206.  
  2207.       case ST_DISC:            /* Discarded */
  2208.         move(CW_ERR,22); printw("File discarded");
  2209.         clrtoeol(); refresh();
  2210.         return;
  2211.  
  2212.       case ST_INT:               /* Interrupted */
  2213.         move(CW_ERR,22); printw("Transfer interrupted");
  2214.         clrtoeol(); refresh();
  2215.         return;
  2216.  
  2217.       case ST_SKIP:            /* Skipped */
  2218.         move(CW_ERR,22); printw("File skipped");
  2219.         clrtoeol(); refresh();
  2220.         return;
  2221.  
  2222.       case ST_ERR:            /* Error message */
  2223.         move(CW_ERR,22); printw("%s",s);
  2224.         clrtoeol(); refresh();
  2225.         return;
  2226.  
  2227.       case ST_REFU:            /* Refused */
  2228.         move(CW_ERR,22);
  2229.         if (*s)
  2230.           printw("Refused, %s",s);
  2231.         else printw("Refused");
  2232.         clrtoeol(); refresh();
  2233.         return;
  2234.  
  2235.       case ST_INC:
  2236.         move(CW_ERR,22); printw("Incomplete");
  2237.         clrtoeol(); refresh();
  2238.         return;
  2239.  
  2240.       default:            /* Bad call */
  2241.         move(CW_ERR,22); printw("*** screen() called with bad status ***");
  2242.         clrtoeol(); refresh(); return;
  2243.     }
  2244.  
  2245.       case SCR_TC:                /* Transaction complete */    
  2246.     move(CW_MSG,22);        /* Print statistics in message line */
  2247.     if (tsecs > 0)
  2248.       printw("Files: %ld, Total Bytes: %ld, %ld cps",
  2249.          fcnt, fbyt, ((fbyt * 10L) / (long) tsecs) / 10L);
  2250.     else printw("Files: %ld, Total Bytes: %ld",fcnt,fbyt);
  2251.     clrtoeol();
  2252.     move(CW_TR, 1);
  2253.     printw("       Elapsed Time: %s",hhmmss((long)tsecs));
  2254.     clrtoeol();
  2255.     move(23,0); clrtoeol();        /* Clear instructions lines */
  2256.     move(22,0); clrtoeol();        /* to make room for prompt. */
  2257.     refresh();
  2258. #ifndef VMSCURSE
  2259.     endwin();
  2260. #endif /* VMSCURSE */
  2261.     pct = 100; oldpct = 0;        /* Reset these for next time. */
  2262.     oldtyp = 0; oldwin = -1; oldtry = -1; oldlen = -1;
  2263.     cendw = 1; conoc(BEL);        /* Close window, then beep. */
  2264.     ft_win = 0;            /* Window closed. */
  2265.     return;
  2266.  
  2267.       case SCR_EM:            /* Error packet (fatal) */
  2268.     move (CW_ERR,22);
  2269.     printw("? %s",s);
  2270.     conoc(BEL);
  2271.     clrtoeol(); refresh(); return;
  2272.  
  2273.       case SCR_QE:            /* Quantity equals */
  2274.       case SCR_TU:            /* Undelimited text */
  2275.       case SCR_TN:            /* Text delimited at start */
  2276.       case SCR_TZ:            /* Text delimited at end */
  2277.     return;                /* (ignored in fullscreen display) */
  2278.  
  2279.       case SCR_XD:                /* X-packet data */
  2280.     move(CW_NAM,22);
  2281.     printw("%s",s);
  2282.     clrtoeol(); refresh(); return;
  2283.  
  2284.       case SCR_CW:            /* Close Window */
  2285.     clrtoeol(); move(23,0); clrtoeol(); move(22,0);    clrtoeol();
  2286.     refresh();
  2287.     pct = 100; oldpct = 0;        /* Reset these for next time. */
  2288.     oldtyp = 0; oldwin = -1; oldtry = -1; oldlen = -1;
  2289.  
  2290. #ifndef VMSCURSE
  2291.     endwin();
  2292. #endif /* VMSCURSE */
  2293.     ft_win = 0;            /* Flag that window is closed. */
  2294.     cendw = 1; return;
  2295.  
  2296.       case SCR_CD:            /* Display current directory */
  2297.     move(CW_DIR,22); printw(s);
  2298.     clrtoeol(); refresh(); return;    
  2299.  
  2300.       default:                /* Bad call */
  2301.     move (CW_ERR,22);
  2302.     printw("*** screen() called with bad function code ***");
  2303.     clrtoeol(); refresh(); return;
  2304.     }
  2305. }
  2306. #endif /* CK_CURSES */
  2307.  
  2308. #endif /* MAC */
  2309.